# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

########################################################################
# OPENAPI-URI: /api/bio/newtimers
########################################################################
# get:
#   responses:
#     '200':
#       content:
#         application/json:
#           schema:
#             $ref: '#/components/schemas/Biography'
#       description: 200 Response
#     default:
#       content:
#         application/json:
#           schema:
#             $ref: '#/components/schemas/Error'
#       description: unexpected error
#   security:
#   - cookieAuth: []
#   summary: Shows some facts about a contributor
# post:
#   requestBody:
#     content:
#       application/json:
#         schema:
#           $ref: '#/components/schemas/defaultWidgetArgs'
#   responses:
#     '200':
#       content:
#         application/json:
#           schema:
#             $ref: '#/components/schemas/Biography'
#       description: 200 Response
#     default:
#       content:
#         application/json:
#           schema:
#             $ref: '#/components/schemas/Error'
#       description: unexpected error
#   security:
#   - cookieAuth: []
#   summary: Shows some facts about a contributor
#
########################################################################


"""
This is the newtimers list renderer for Kibble
"""

import json
import time
import hashlib


def find_earlier(session, query, when, who, which, where, doctype, dOrg):
    """Find earlier document pertaining to this user. return True if found"""
    if "aggs" in query:
        del query["aggs"]

    rangeQuery = {"range": {which: {"from": 0, "to": time.time()}}}

    query["query"]["bool"]["must"] = [
        rangeQuery,
        {"term": {"organisation": dOrg}},
        {"term": {where: who}},
    ]
    query["size"] = 1
    query["sort"] = [{which: "asc"}]

    res = session.DB.ES.search(index=session.DB.dbname, doc_type=doctype, body=query)
    if res["hits"]["hits"]:
        doc = res["hits"]["hits"][0]["_source"]
        if doc[which] >= when:
            return [doc[which], doc]
        else:
            return [-1, None]
    else:
        return [-1, None]


def run(API, environ, indata, session):

    # We need to be logged in for this!
    if not session.user:
        raise API.exception(403, "You must be logged in to use this API endpoint! %s")

    now = time.time()

    # First, fetch the view if we have such a thing enabled
    viewList = []
    if indata.get("view"):
        viewList = session.getView(indata.get("view"))
    if indata.get("subfilter"):
        viewList = session.subFilter(indata.get("subfilter"), view=viewList)

    dOrg = session.user["defaultOrganisation"] or "apache"

    # Keep track of all contributors, and newcomers
    contributors = []
    newcomers = {}

    ####################################################################
    # Start by grabbing all contributors this period via terms agg     #
    ####################################################################
    dateTo = indata.get("to", int(time.time()))
    dateFrom = indata.get(
        "from", dateTo - (86400 * 30 * 6)
    )  # Default to a 6 month span

    ############################
    # CODE NEWTIMERS           #
    ############################
    rangeKey = "ts"
    rangeQuery = {"range": {rangeKey: {"from": dateFrom, "to": dateTo}}}

    query = {
        "query": {"bool": {"must": [rangeQuery, {"term": {"organisation": dOrg}}]}}
    }

    query["aggs"] = {
        "by_committer": {"terms": {"field": "committer_email", "size": 500}},
        "by_author": {"terms": {"field": "author_email", "size": 500}},
    }

    # Source-specific or view-specific??
    if indata.get("source"):
        query["query"]["bool"]["must"].append(
            {"term": {"sourceID": indata.get("source")}}
        )
    elif viewList:
        query["query"]["bool"]["must"].append({"terms": {"sourceID": viewList}})

    res = session.DB.ES.search(
        index=session.DB.dbname, doc_type="code_commit", body=query
    )

    code_contributors = []
    for bucket in res["aggregations"]["by_committer"]["buckets"]:
        email = bucket["key"]
        if email not in code_contributors:
            code_contributors.append(email)

    for bucket in res["aggregations"]["by_author"]["buckets"]:
        email = bucket["key"]
        if email not in code_contributors:
            code_contributors.append(email)

    # Now, for each contributor, find if they have done anything before
    for email in code_contributors:
        ea = find_earlier(
            session, query, dateFrom, email, "ts", "author_email", "code_commit", dOrg
        )
        ec = find_earlier(
            session,
            query,
            dateFrom,
            email,
            "ts",
            "committer_email",
            "code_commit",
            dOrg,
        )
        if ea[0] != -1 and ec[0] != -1:
            earliest = ea
            if earliest[0] == -1 or (earliest[0] > ec[0] and ec[0] != -1):
                earliest = ec
            newcomers[email] = {"code": earliest}

    ############################
    # ISSUE NEWTIMERS          #
    ############################
    rangeKey = "created"
    rangeQuery = {"range": {rangeKey: {"from": dateFrom, "to": dateTo}}}

    query = {
        "query": {"bool": {"must": [rangeQuery, {"term": {"organisation": dOrg}}]}}
    }

    query["aggs"] = {
        "by_creator": {"terms": {"field": "issueCreator", "size": 500}},
        "by_closer": {"terms": {"field": "issueCloser", "size": 500}},
    }

    # Source-specific or view-specific??
    if indata.get("source"):
        query["query"]["bool"]["must"].append(
            {"term": {"sourceID": indata.get("source")}}
        )
    elif viewList:
        query["query"]["bool"]["must"].append({"terms": {"sourceID": viewList}})

    res = session.DB.ES.search(index=session.DB.dbname, doc_type="issue", body=query)

    issue_contributors = []
    for bucket in res["aggregations"]["by_creator"]["buckets"]:
        email = bucket["key"]
        if email not in issue_contributors:
            issue_contributors.append(email)

    for bucket in res["aggregations"]["by_closer"]["buckets"]:
        email = bucket["key"]
        if email not in issue_contributors:
            issue_contributors.append(email)

    # Now, for each contributor, find if they have done anything before
    for email in issue_contributors:
        ecr = find_earlier(
            session, query, dateFrom, email, "created", "issueCreator", "issue", dOrg
        )
        ecl = find_earlier(
            session, query, dateFrom, email, "closed", "issueCloser", "issue", dOrg
        )
        if ecr[0] != -1 and ecl[0] != -1:
            earliest = ecr
            if earliest[0] == -1 or (earliest[0] > ecl[0] and ecl[0] != -1):
                earliest = ecl
            newcomers[email] = newcomers.get(email, {})
            newcomers[email]["issue"] = earliest

    email_contributors = []

    ################################
    # For each newtimer, get a bio #
    ################################

    for email in newcomers:
        pid = hashlib.sha1(
            ("%s%s" % (dOrg, email)).encode("ascii", errors="replace")
        ).hexdigest()
        person = {}
        if session.DB.ES.exists(index=session.DB.dbname, doc_type="person", id=pid):
            person = session.DB.ES.get(
                index=session.DB.dbname, doc_type="person", id=pid
            )["_source"]
        person["md5"] = hashlib.md5(
            person["email"].encode("utf-8")
        ).hexdigest()  # gravatar needed for UI!
        newcomers[email]["bio"] = person

    newcomers_code = []
    newcomers_issues = []
    newcomers_email = []

    # Count newcomers in each category (TODO: put this elsewhere earlier)
    for email, entry in newcomers.items():
        if "code" in entry:
            newcomers_code.append(email)
        if "issue" in entry:
            newcomers_issues.append(email)
        if "email" in entry:
            newcomers_email.append(email)

    JSON_OUT = {
        "okay": True,
        "stats": {
            "code": {"newcomers": newcomers_code, "seen": len(code_contributors)},
            "issues": {"newcomers": newcomers_issues, "seen": len(issue_contributors)},
            "email": {"newcomers": newcomers_email, "seen": len(email_contributors)},
        },
        "bios": newcomers,
        "responseTime": time.time() - now,
    }
    yield json.dumps(JSON_OUT, indent=2)
